package com.atguigu.gmall.payment.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeCloseRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.enums.model.OrderStatus;
import com.atguigu.gmall.enums.model.PaymentStatus;
import com.atguigu.gmall.enums.model.PaymentType;
import com.atguigu.gmall.order.client.OrderFeignClient;
import com.atguigu.gmall.order.model.OrderInfo;
import com.atguigu.gmall.payment.config.AlipayConfig;
import com.atguigu.gmall.payment.model.PaymentInfo;
import com.atguigu.gmall.payment.service.AlipayService;
import com.atguigu.gmall.payment.service.PaymentInfoService;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

@Service
@Slf4j
@SuppressWarnings("all")
public class AlipayServiceImpl implements AlipayService {

    @Autowired
    private OrderFeignClient orderFeignClient;
    @Autowired
    private PaymentInfoService paymentInfoService;
    @Autowired
    private AlipayClient alipayClient;
    @Autowired
    private RabbitService rabbitService;

    /**
     * 调用支付宝接口产生支付页面
     * @param orderId 订单id
     * @return 返回支付宝支付页面
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createAlipayForm(Long orderId) {
        try {
            //1.远程调用订单微服务获取订单信息,验证订单支付状态
            OrderInfo orderInfo = orderFeignClient.getOrderInfoByOrderId(orderId);
            if(orderInfo != null && OrderStatus.UNPAID.name().equals(orderInfo.getOrderStatus())){
    
                //2.构建本地交易记录对象,将交易记录对象保存
                PaymentInfo paymentInfo = new PaymentInfo();
    
                //2.1给本地交易记录封装属性
                paymentInfo.setOutTradeNo(orderInfo.getOutTradeNo()); //对外业务编号
                paymentInfo.setOrderId(orderId); //订单编号
                paymentInfo.setUserId(orderInfo.getUserId()); //用户id
                paymentInfo.setPaymentType(PaymentType.ALIPAY.name()); //支付类型（支付宝)
                paymentInfo.setSubject(orderInfo.getTradeBody()); //商品描述
                paymentInfo.setTotalAmount(new BigDecimal(0.01));
    
                //2.1保存本地交易记录
                paymentInfoService.savePaymentInfo(paymentInfo, PaymentStatus.UNPAID.name());
    
                //3.调用支付宝,展示支付页面接口得到渲染后html页面
                AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
                //异步接收地址，仅支持http/https，公网可访问,支付宝平台调用商城系统,用来通知商城支付结果回调地址
                request.setNotifyUrl(AlipayConfig.notify_payment_url);
                //同步跳转地址，仅支持http/https,用户付款后展示成功页面
                request.setReturnUrl(AlipayConfig.return_payment_url);
                /******必传参数******/
                JSONObject bizContent = new JSONObject();
                //商户订单号，商家自定义，保持唯一性
                bizContent.put("out_trade_no",orderInfo.getOutTradeNo());
                //支付金额，最小值0.01元
                bizContent.put("total_amount", 0.01);
                //订单标题，不可使用特殊符号
                bizContent.put("subject", orderInfo.getTradeBody());
                //电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY
                bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
    
                /******可选参数******/
                bizContent.put("timeout_express","10m");
    
                //商品明细信息，按需传入
                JSONObject extendParams = new JSONObject();
                extendParams.put("orderId", orderId);
                bizContent.put("extendParams", extendParams);
                request.setBizContent(bizContent.toString());
                
                AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
                if(response.isSuccess()){
                    System.err.println(response.getBody());
                    return response.getBody();
                }
            }
            return null;
        } catch (Exception e) {
            log.error("[支付服务],产生支付宝支付二维码页面异常:{},订单ID{}",e,orderId);
            throw new RuntimeException(e);
        }
    }

    /**
     * 支付宝处理完成用户支付成功后,异步通知支付结果给用户
     * @param paramsMap 支付提交参数
     * @return 支付结果
     */
    @Override
    public String notifyGmallResult(Map<String, String> paramsMap) {
        try {
            //1.业务校验
            //1.1调用支付宝SDK签名验证
            boolean signVerified = AlipaySignature.rsaCheckV1(paramsMap,AlipayConfig.alipay_public_key,AlipayConfig.charset,AlipayConfig.sign_type);
            if(signVerified){
                //验证订单是否为商家,通过订单查询订单金额,校验商户端交易记录金额是否和支付宝端金额是否一致
                String outTradeNo = paramsMap.get("out_trade_no");
                PaymentInfo paymentInfo = paymentInfoService.getPaymentInfoByOutTradeNo(outTradeNo,PaymentType.ALIPAY.name());
                //验证appId是否为商家的
                if(paymentInfo != null){
                    BigDecimal totalAmount = paymentInfo.getTotalAmount();
                    String alipayTotalAmount = paramsMap.get("total_amount");
                    if(totalAmount.compareTo(new BigDecimal(alipayTotalAmount)) == 0){
                        //判断支付宝支付交易结果
                        String tradeStatus = paramsMap.get("trade_status");
                        //如果支付宝响应支付结果成功,修改本地交易记录状态
                        if("TRADE_SUCCESS".equals(tradeStatus)){
                            this.paySuccess(paymentInfo,paramsMap);
                            return "success";
                        }
                    }
                }
            }
            return "fail";
        } catch (AlipayApiException e) {
            return "fail";
        }
    }

    /**
     * 根据支付凭证修改支付状态
     * @param paymentInfo 支付记录凭证
     * @param paramsMap 传入的支付方式
     */
    private void paySuccess(PaymentInfo paymentInfo, Map<String, String> paramsMap) {
        //1.查询支付宝支付交易记录凭证
        String tradeNo = paramsMap.get("trade_no");
        paymentInfo.setTradeNo(tradeNo);
        paymentInfo.setCallbackTime(new Date());
        paymentInfo.setCallbackContent(paramsMap.toString());

        //2.修改本地交易记录状态
        paymentInfo.setPaymentStatus(PaymentStatus.PAID.name());
        paymentInfoService.updateById(paymentInfo);

        //3.发送消息到MQ通知订单微服务修改订单状态
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_PAY, MqConst.ROUTING_PAYMENT_PAY, paymentInfo.getOrderId());
    }

    /**
     * 上方协商一致后,根据用户提交订单id退款
     * @param orderId 订单id
     */
    @Override
    public void refund(Long orderId) {
        try {
            //1.将本地交易记录关闭
            LambdaUpdateWrapper<PaymentInfo> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(PaymentInfo::getOrderId, orderId);
            updateWrapper.eq(PaymentInfo::getPaymentType, PaymentType.ALIPAY.name());
            PaymentInfo paymentInfo = paymentInfoService.getOne(updateWrapper);
            if(paymentInfo != null && PaymentStatus.PAID.name().equals(paymentInfo.getPaymentStatus())){

                //2.调用支付宝退款接口
                AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
                JSONObject bizContent = new JSONObject();
                if(StringUtils.isNotBlank(paymentInfo.getTradeNo())){
                    //退款订单编号
                    bizContent.put("trade_no", paymentInfo.getTradeNo());
                }
                    //退款订单金额
                    bizContent.put("refund_amount",paymentInfo.getTotalAmount());
                    //退款编号:要求唯一
                    bizContent.put("out_request_no", UUID.randomUUID().toString());
                    //退款原因
                    bizContent.put("refund_reason", "双方协商一致,可退款");
                    request.setBizContent(bizContent.toString());

                // 返回参数选项，按需传入
                AlipayTradeRefundResponse response = alipayClient.execute(request);
                if(response.isSuccess()){
                    String fundChange = response.getFundChange();
                    if("Y".equals(fundChange)){
                        //退款成功后修改本地交易记录状态
                        updateWrapper.set(PaymentInfo::getPaymentStatus, PaymentStatus.CLOSED);
                        paymentInfoService.update(updateWrapper);
                    }
                }
            }
        } catch (Exception e) {
            log.error("[支付服务]退款异常:{},订单Id:",e,orderId);
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据支付宝交易号关闭支付宝交易(就是让页面二维码失效)
     * @param tradeNo
     * @param outTradeNo
     */
    @Override
    public void closeZhiFuBaoTrade(String tradeNo, String outTradeNo) {
        try {
            AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
            JSONObject bizContent = new JSONObject();
            if(org.apache.commons.lang.StringUtils.isNotBlank(tradeNo)){
                bizContent.put("trade_no", tradeNo);
            }
            if(org.apache.commons.lang.StringUtils.isNotBlank(outTradeNo)){
                bizContent.put("out_notrade_no",outTradeNo);
            }
            request.setBizContent(bizContent.toString());
            alipayClient.execute(request);
        } catch (Exception e) {
            log.error("[支付服务]查询支付宝交易失败:{}",e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据支付宝交易号,查询支付宝交易状态
     * @param tradeNo
     * @param outTradeNo
     * @return
     */
    @Override
    public String getZhiFuBaoTradeStatus(String tradeNo, String outTradeNo) {
        try {
            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
            JSONObject bizContent = new JSONObject();
            if(StringUtils.isNotBlank(tradeNo)){
                bizContent.put("rade_no",tradeNo);
            }
            if(StringUtils.isNotBlank(outTradeNo)){
                bizContent.put("out_trade_no", outTradeNo);
            }
            request.setBizContent(bizContent.toString());
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            if(response.isSuccess()){
                String tradeStatus = response.getTradeStatus();
                return tradeStatus;
            }
            return null;
        } catch (Exception e) {
            log.error("[支付服务],查询支付宝交易失败:{}",e);
            throw new RuntimeException(e);
        }
    }
}